package mdp.algorithm.explore.P;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack;

import javax.swing.JLabel;
import javax.swing.Timer;

import mdp.algorithm.fastestPath.PathSolver;
import mdp.algorithm.simulator.Maze;
import mdp.algorithm.simulator.Stopwatch;
import mdp.algorithm.simulator.TimerQueue;

public class Exploration implements Runnable{
	
	private Stopwatch s;
	private int robotOrientation;
	private int robotMidPointRow;
	private int robotMidPointCol;
	private Maze maze;
	private Stack<Position> stack;
	private Position temp;
	private JLabel exploreTimeValue;
	private String timeLimit;
	private String tempStr;
	private float tempFloat;
	private float timeLimitFloat;
	private Timer timer;
	private int i = 0;
	private boolean status = false;
	private boolean backtrack = false;
	int[][] visited = new int[22][17]; //0 mean not visted, 1 means visted
	private boolean goal = false;
	private boolean end = false;
	private float percentMap;
	private int speed;
	
	public Exploration(Maze mazeMap, JLabel exploreTimeValue, String timeLimit, float percentMap, float speed){
		s = new Stopwatch();
		maze = mazeMap;
		stack = new Stack<Position>();
		robotOrientation = maze.getRobotOrientation();
		robotMidPointRow = maze.getRobotMidPointRow();
		robotMidPointCol = maze.getRobotMidPointCol();
		temp = new Position(robotMidPointRow, robotMidPointCol, robotOrientation);
		stack.push(temp);
		
		for(int i=0; i<21; i++){
			for(int j=0; j<16; j++){
				visited[i][j] = 0; 
			}
		}
		this.percentMap = percentMap;
		this.exploreTimeValue = exploreTimeValue;
		System.out.println("perMap" + percentMap);
		this.timeLimit = timeLimit;
		this.speed =(int)(speed*1000);
	}
	
	public void explorePath(){
		tempStr = timeLimit.substring(0, 1);
		timeLimitFloat = Integer.parseInt(tempStr);
		tempStr = timeLimit.substring(2, 4);
		tempFloat = Float.parseFloat(tempStr) * 1/60;
		timeLimitFloat = timeLimitFloat + tempFloat;
		
		s.startStopwatchTimer(exploreTimeValue, timeLimitFloat);
		startTimer();
	}

	private void startTimer(){
		timer = new Timer(speed, new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				if(stack.isEmpty() || maze.percentageExplored() >= percentMap || exploreTimeValue.getText().equals("0"+timeLimit)){
					stopExplore();
					s.stopStopwatchTimer();
		  			System.out.print("end1");
		  		}
				else{
					if(status){
						explorePathAction();
						status = false;
					}
					else{
						setExploreAction();
						status = true;
					}
		    	}
			}
		});
		timer.start();
	}
	
	public void setExploreAction(){
		maze.setExplorationPathAction();
	}
	
	public void explorePathAction(){
		//North
		robotMidPointRow = maze.getRobotMidPointRow();
		robotMidPointCol = maze.getRobotMidPointCol();
		visited[robotMidPointRow-1][robotMidPointCol-1] = 1;
		visited[robotMidPointRow-1][robotMidPointCol] = 1;
		visited[robotMidPointRow-1][robotMidPointCol+1] = 1;
		visited[robotMidPointRow][robotMidPointCol-1] = 1;
		visited[robotMidPointRow][robotMidPointCol] = 1;
		visited[robotMidPointRow][robotMidPointCol+1] = 1;
		visited[robotMidPointRow+1][robotMidPointCol-1] = 1;
		visited[robotMidPointRow+1][robotMidPointCol] = 1;
		visited[robotMidPointRow+1][robotMidPointCol+1] = 1;
		
		if(!goal)
			goal = checkGoal(robotMidPointRow, robotMidPointCol);
		
		if(maze.checkFrontClear(visited)){
			backtrack = false;
			maze.moveForwardAction();
			robotMidPointRow = maze.getRobotMidPointRow();
			robotMidPointCol = maze.getRobotMidPointCol();
			robotOrientation = maze.getRobotOrientation();
			stack.push(new Position(robotMidPointRow, robotMidPointCol, robotOrientation));
		}
		else if(maze.checkLeftClear(visited)){
			backtrack = false;
			maze.spinLeftAction();
		}
		else if(maze.checkRightClear(visited)){
			backtrack = false;
			maze.spinRightAction();
		}
		else{
			System.out.println("test");
			backtrack = true;
			Position last = stack.pop();
			
			switch (last.getOri()) {
			case 0:
				switch (maze.getRobotOrientation()) {
				case 0:
                	maze.spinLeftAction();
                	maze.spinLeftAction();
                	break;
                case 1:
                	maze.spinRightAction();
                	break;
                case 2:
                	break;
                case 3:
                	maze.spinLeftAction();
                	break;
				}
				break;
			case 1:
				switch (maze.getRobotOrientation()) {
				case 0:
                	maze.spinLeftAction();
                	break;
                case 1:
                	maze.spinRightAction();
                	maze.spinRightAction();
                	break;
                case 2:
                	maze.spinRightAction();
                	break;
                case 3:
                	break;
				}
				break;
			case 2:
				switch (maze.getRobotOrientation()) {
				case 0:
                	break;
                case 1:
                	maze.spinLeftAction();
                	break;
                case 2:
                	maze.spinRightAction();
                	maze.spinRightAction();
                	break;
                case 3:
                	maze.spinRightAction();
                	break;
				}
				break;
			case 3:
				switch (maze.getRobotOrientation()) {
				case 0:
					maze.spinRightAction();
                	break;
                case 1:
                	break;
                case 2:
                	maze.spinLeftAction();
                	break;
                case 3:
                	maze.spinRightAction();
                	maze.spinRightAction();
                	break;
				}
				break;
			}
			
			if (!stack.isEmpty()) {
				System.out.print("here");
				maze.checkFrontObstaclesClear();
                maze.moveForwardAction();
            }
            else
            {
            	end=true;
            	System.out.print("done");
            }
			
		}
	}
	
	private void stopExplore(){
		Point start = new Point(maze.getRobotMidPointRow(), maze.getRobotMidPointCol());
        maze.startTimer();
//        System.out.println(start.toString());
//		if(!goal){
//			System.out.println("path1");
//	        Point goal1 = new Point(2,14);
//	        PathSolver ps1 = new PathSolver();
//	        System.out.println(start.toString()+" to "+goal1.toString());
//			ps1.moveRobot(ps1.solvePath(start,goal1,maze,maze.getRobotOrientation()),start,goal1,maze,maze.getRobotOrientation());
//			start.setLocation(2,14);
//		}
//		System.out.println("path2");
        
        if((maze.checkExplored(2,13)||maze.checkExplored(3,14))&&maze.checkUnexplored(2,14)){
        	PathSolver ps1 = new PathSolver();
        	Point goal1 = new Point(2,14);
    		ps1.moveRobot(ps1.solvePath(start,goal1,maze,maze.getRobotOrientation()),start,goal1,maze,maze.getRobotOrientation());
        }
        
        //go to start
		Point goal2 = new Point(19,2);
        PathSolver ps2 = new PathSolver();
		ps2.moveRobot(ps2.solvePath(start,goal2,maze,maze.getRobotOrientation()),start,goal2,maze,maze.getRobotOrientation());
		maze.completePath();
		timer.stop();
	}
	public void stopExploreStopwatchTimer(){
		s.stopStopwatchTimer();
		s.resetStopwatchTimer();
	}
	
	public void stopTimer(){
		timer.stop();
	}
	
	public void clearStack(){
        stack.clear();
    }
	
	private boolean checkGoal(int midpointRow, int midpointCol){
		if(midpointRow==2 && midpointCol == 14)
			return true;
		return false;
	}
	
	@Override
    public void run() {
        // TODO Auto-generated method stub
		explorePath();
    }
}